package com.txtsqlclient.ui;

import java.util.ArrayList;
import java.util.List;

/**
 * @author spadda
 */
public class TabularLayoutHelper {

    private static String newLine = System.getProperty("line.separator");

    private static String getRowSeparator(int width, int numOfCols, char rowSeparator) {
        StringBuilder buff = new StringBuilder();
        // Add colWidth + 1 '-'s. The extra one is for the column separator '|'.
        for (int i = 0; i < width + numOfCols; i++) {
            buff.append(rowSeparator);
        }
        buff.append(newLine);
        return buff.toString();
    }

    public static String print(List<List<String>> data, int width) {
        int[] colWidths = getColumnWidths(data, width);
        int totalRows = data.get(0).size();
        StringBuilder buff = new StringBuilder();
        String rowSeparator = getRowSeparator(width, colWidths.length, '-');
        buff.append(rowSeparator);
        for (int rowNum = 0; rowNum < totalRows; rowNum++) {
            List<String> row = new ArrayList<String>();
            for (List<String> column : data) {
                row.add(column.get(rowNum));
            }
            buff.append(getFormattedRow(row, colWidths, '|'));
            buff.append(rowSeparator);
        }
        return buff.toString();
    }

    public static int[] getColumnWidths(List<List<String>> data, int width) {
        int[] colWidths = new int[data.size()];
        float[] avgWidths = new float[data.size()];
        float totalOfAvgs = 0;
        for (int i = 0; i < colWidths.length; i++) {
            List<String> column = data.get(i);
            float total = 0;
            for (String cell : column) {
                total += cell != null
                        ? cell.length()
                        : 0;
            }
            float avg = total / column.size();
            avgWidths[i] = avg;
            totalOfAvgs += avg;
        }
        for (int i = 0; i < colWidths.length; i++) {
            colWidths[i] = (int) ((avgWidths[i] * width) / totalOfAvgs);
            if (colWidths[i] == 0) {
                colWidths[i] = 1;
            }
        }
        return colWidths;
    }

    public static String getFormattedRow(List<String> row, int[] colWidths, char colSeparator) {
        StringBuilder buff = new StringBuilder();
        boolean[] done = new boolean[colWidths.length];
        int lineNum = 0;
        outer: while (true) {
            int i = 0;
            for (String cell : row) {
                int width = colWidths[i];
                if (done[i]) {
                    // TODO: If there are no more chars to be printed for this column, print
                    // 'width' number of empty spaces.
                    String s = String.format("%1$-" + width + "s", "");
                    buff.append(s);
                } else {
                    // If there are any more chars to be printed for this column.
                    int numOfCharsPrinted = lineNum * width;
                    // TODO: If this is the last line on which any chars from this column can
                    // be printed. Pad the rest of the chars with empty spaces.
                    if (cell == null) {
                        String s = String.format("%1$-" + width + "s", "");
                        buff.append(s);
                        done[i] = true;
                    } else if (numOfCharsPrinted + width >= cell.length()) {
                        String s = String.format("%1$-" + width + "s",
                                cell.substring(numOfCharsPrinted));
                        buff.append(s);
                        done[i] = true;
                    } else {
                        // There are still more chars to be printed from this column.
                        buff.append(cell.substring(numOfCharsPrinted, numOfCharsPrinted
                                + width));
                        done[i] = false;
                    }
                }
                buff.append(colSeparator);
                i++;
            }
            for (boolean d : done) {
                // If at least one of the columns is not done, continue printing to the next
                // line.
                if (!d) {
                    buff.append(newLine);
                    lineNum++;
                    continue outer;
                }
            }
            // If all the columns are fully populated, break.
            break outer;
        }
        buff.append(newLine);
        return buff.toString();
    }

}
